/*
 * Created on 2005-8-3
 *
 */
package bma.common.langutil.bean;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

import bma.common.langutil.bean.common.CommonClassDialect;
import bma.common.langutil.bean.impl.BeanClassBuilderNative;
import bma.common.langutil.bean.packagefw.PackaheHandlerPojoClassBuilder;
import bma.common.langutil.core.ObjectUtil;

/**
 * 
 * @author guanzhong
 * @since 1.0 (imported from BMA.ESP Project)
 * 
 */
public class BeanSystem {

	final org.slf4j.Logger log = org.slf4j.LoggerFactory
			.getLogger(BeanSystem.class);

	private static BeanSystem instance = new BeanSystem();

	public static BeanSystem getInstance() {
		return instance;
	}

	protected Map<String, BeanClass> classes = new ConcurrentHashMap<String, BeanClass>();
	protected List<BeanClassBuilder> builders = new CopyOnWriteArrayList<BeanClassBuilder>();

	protected PackaheHandlerPojoClassBuilder ph = new PackaheHandlerPojoClassBuilder();
	protected BeanClassBuilderNative nativeBuilder = new BeanClassBuilderNative();

	public BeanSystem() {
		super();

		BeanClassBuilderNative bcb = new BeanClassBuilderNative();
		bcb.setDialect(new CommonClassDialect());
		nativeBuilder = bcb;
	}

	public boolean has(Class cls) {
		for (BeanClassBuilder old : builders) {
			if (ObjectUtil.equals(old.getClass(), cls)) {
				return true;
			}
		}
		return false;
	}

	public boolean add(BeanClassBuilder c) {
		if (builders.contains(c))
			return false;
		builders.add(c);
		return true;
	}

	public boolean remove(BeanClassBuilder c) {
		return builders.remove(c);
	}

	public BeanClassBuilderNative getNativeBuilder() {
		return nativeBuilder;
	}

	public BeanClass getBeanClass(Class cls) {
		return getBeanClass(cls, true);
	}

	public BeanClass getBeanClass(Class cls, boolean build) {
		BeanClass pojo = lookupBeanClass(cls);
		if (pojo == null && build) {
			for (BeanClassBuilder b : this.builders) {
				try {
					pojo = b.createClass(cls);
				} catch (Exception e) {
					log.warn(b + " createClass(" + cls.getName() + ") fail", e);
				}
				if (pojo != null)
					break;
			}
			if (pojo == null) {
				try {
					pojo = nativeBuilder.createClass(cls);
				} catch (Exception e) {
					log.warn(nativeBuilder + " createClass(" + cls.getName()
							+ ") fail", e);
				}
			}

			if (pojo != null) {
				setBeanClass(cls, pojo);
			}
		}
		return pojo;
	}

	private void setBeanClass(Class cls, BeanClass pojoClass) {
		classes.put(cls.getName(), pojoClass);
	}

	public BeanClass lookupBeanClass(Class cls) {
		return classes.get(cls.getName());
	}

}
